﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Web;

namespace FL.Web.BackEnd.Helper
{
    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    //以下枚举指定报表数据的格式类型
    public enum ResponseDataType
    {
        PlainText, //报表数据为XML或JSON文本，在调试时可以查看报表数据。数据未经压缩，大数据量报表采用此种方式不合适
        ZipBinary, //报表数据为XML或JSON文本经过压缩得到的二进制数据。此种方式数据量最小(约为原始数据的1/10)，但用Ajax方式加载报表数据时不能为此种方式
        ZipBase64, //报表数据为将 ZipBinary 方式得到的数据再进行 BASE64 编码的数据。此种方式适合用Ajax方式加载报表数据
    };
    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    //class XMLReportData 产生报表需要的xml数据
    public class XmlReportData
    {

        //根据DataSet, 产生提供给报表需要的XML数据，参数ToCompress指定是否压缩数据
        public static void GenDetailData(System.Web.UI.Page dataPage, DataSet myds, bool toCompress)
        {
            GenDetailData(dataPage.Response, myds, toCompress);
        }

        public static void GenDetailData(HttpResponse response, DataSet myds, bool toCompress)
        {
            string xmlText = myds.GetXml();
            ResponseXml(response, ref xmlText, toCompress);
        }

        public static string GenDetailData(DataSet myds)
        {
            var bb = myds.GetXml();
            return bb;
        }

        //根据DataTable, 产生提供给报表需要的XML数据，参数ToCompress指定是否压缩数据
        public static void GenDetailData(System.Web.UI.Page dataPage, DataTable mydt, bool toCompress)
        {
            GenDetailData(dataPage.Response, mydt, toCompress);
        }

        public static void GenDetailData(HttpResponse response, DataTable mydt, bool toCompress)
        {
            var ds = new DataSet();
            ds.Tables.Add(mydt);
            GenDetailData(response, ds, toCompress);
        }
        public static string GenDetailData(DataTable mydt)
        {
            var ds = new DataSet();
            ds.Tables.Add(mydt);
            //_x0032_0 20    _x0034_0 40
            return GenDetailData(ds);
        }

        public static string FilterZero(DataSet myds)
        {
            var xmlStr = myds.GetXml().Replace(">0.00<", "><").Replace(">0<", "><").Replace(">0.000000<", "><");
            return xmlStr;
        }
        public static string FilterZero(DataTable mydt)
        {
            var xmlStr = GenDetailData(mydt).Replace(">0.00<", "><").Replace(">0<", "><").Replace(">0.000000<", "><");
            return xmlStr;
        }

        //根据DataSet, 产生提供给报表需要的XML数据，并同时将ParamterPart中的报表参数数据一起打包，参数ToCompress指定是否压缩数据
        public static void GenEntireData(System.Web.UI.Page dataPage, DataSet myds, ref string parameterPart,
            bool toCompress)
        {
            GenEntireData(dataPage.Response, myds, ref parameterPart, toCompress);
        }

        public static void GenEntireData(HttpResponse response, DataSet myds, ref string parameterPart,
            bool toCompress)
        {
            string recordsetPart = myds.GetXml();
            string xmlText = "<report>\r\n" + recordsetPart + parameterPart + "</report>";
            ResponseXml(response, ref xmlText, toCompress);
        }

        public static string GenEntireData(DataTable detailTable, DataTable parameterTable)
        {
            var ds = new DataSet();
            
            ds.Tables.Add(detailTable);
            //  string dtlXml = GenDetailData(ds);
            string parameterXml = GenParameterText(parameterTable.CreateDataReader());
            return GenEntireData(ds, ref parameterXml);
        }

        public static string GenEntireData(DataTable detailTable, IDictionary<string, object> parameterPart)
        {
            var ds = new DataSet();
            ds.Tables.Add(detailTable);
            //string dtlXml = GenDetailData(ds);
            string parameterXml = GenParameterText(parameterPart);

            return GenEntireData(ds, ref parameterXml);
        }

        public static string GenEntireData(DataTable detailTable, ref string parameterPart)
        {
            var ds = new DataSet();
            ds.Tables.Add(detailTable);
            //  string dtlXml = GenDetailData(ds);
            // string parameterXml = GenParameterText(parameterTable.CreateDataReader());
            return GenEntireData(ds, ref parameterPart);
        }


        public static string GenEntireData(DataSet myds, ref string parameterPart)
        {
            string recordsetPart = myds.GetXml();
            string xmlText = "<report>\r\n" + recordsetPart + "\r\n" + parameterPart + "</report>";
            return xmlText;
        }

        //根据IDataReader, 产生提供给报表需要的XML数据，其中的空值字段也会产生XML节点，参数ToCompress指定是否压缩数据
        public static void GenNodeXmlDataFromReader(System.Web.UI.Page dataPage, IDataReader dr, bool toCompress)
        {
            GenNodeXmlDataFromReader(dataPage.Response, dr, toCompress);
        }

        public static void GenNodeXmlDataFromReader(HttpResponse response, IDataReader dr, bool toCompress)
        {
            string xmlText = "<xml>\n";
            while (dr.Read())
            {
                xmlText += "<row>";
                for (int i = 0; i < dr.FieldCount; ++i)
                {
                    string fldName = dr.GetName(i);
                    if (fldName == "")
                        fldName = "Fld" + i;
                    xmlText += String.Format("<{0}>{1}</{0}>", fldName,
                        HttpUtility.HtmlEncode(dr.GetValue(i).ToString()));
                }
                xmlText += "</row>\n";
            }
            xmlText += "</xml>\n";

            ResponseXml(response, ref xmlText, toCompress);
        }

        public static string GenNodeXmlDataFromReader(IDataReader dr)
        {
            string xmlText = "<xml>\n";
            while (dr.Read())
            {
                xmlText += "<row>";
                for (int i = 0; i < dr.FieldCount; ++i)
                {
                    string fldName = dr.GetName(i);
                    if (fldName == "")
                        fldName = "Fld" + i;
                    xmlText += String.Format("<{0}>{1}</{0}>", fldName,
                        HttpUtility.HtmlEncode(dr.GetValue(i).ToString()));
                }
                xmlText += "</row>\n";
            }
            xmlText += "</xml>\n";

            return xmlText;
        }

        //根据 IDataReader 产生提供给报表需要的XML参数数据包
        public static void GenParameterData(System.Web.UI.Page dataPage, IDataReader drParamer)
        {
            GenParameterData(dataPage.Response, drParamer);
        }

        public static void GenParameterData(HttpResponse response, IDataReader drParamer)
        {
            string xmlText = GenParameterText(drParamer);
            xmlText = "<report>" + xmlText + "</report>";
            ResponseXml(response, ref xmlText, false);
        }

        //将 DataReader 中的数据打包为报表需要的参数数据包形式
        public static string GenParameterText(IDataReader drParamer)
        {
            string parameterPart = "<_grparam>\r\n";
            if (drParamer.Read())
            {
                for (int i = 0; i < drParamer.FieldCount; ++i)
                {
                    if (drParamer.IsDBNull(i))
                        continue;

                    if (drParamer.GetFieldType(i).IsArray)
                    {
                        long dataSize = drParamer.GetBytes(i, 0, null, 0, int.MaxValue);
                        byte[] buffer = new byte[dataSize];
                        drParamer.GetBytes(i, 0, buffer, 0, (int)dataSize);
                        parameterPart += String.Format("<{0}>{1}</{0}>\r\n", drParamer.GetName(i),
                            Convert.ToBase64String(buffer));
                    }
                    else
                    {
                        parameterPart += String.Format("<{0}>{1}</{0}>\r\n", drParamer.GetName(i),
                            HttpUtility.HtmlEncode(drParamer.GetValue(i).ToString()));
                    }
                }
            }
            parameterPart += "</_grparam>\r\n";
            return parameterPart;
        }



        public static string GenParameterText(IDictionary<string, object> drParamer)
        {
            string parameterPart = "\r\n<_grparam>\r\n";
            foreach (var item in drParamer)
            {
                parameterPart += String.Format("<{0}>{1}</{0}>\r\n", item.Key, item.Value);
            }
            parameterPart += "</_grparam>\r\n";
            return parameterPart;


        }
        //将报表XML数据文本输出到HTTP请求
        public static void ResponseXml(System.Web.UI.Page dataPage, ref string xmlText, bool toCompress)
        {
            ResponseXml(dataPage.Response, ref xmlText, toCompress);
        }

        public static void ResponseXml(HttpResponse response, ref string xmlText, bool toCompress)
        {
            //报表XML数据的前后不能附加任何其它数据，否则XML数据将不能成功解析，所以调用ClearContent方法清理网页中前面多余的数据
            response.ClearContent();

            if (toCompress)
            {
                //将string数据转换为byte[]，以便进行压缩
                //System.Text.UnicodeEncoding converter = new System.Text.UnicodeEncoding();
                var converter = new UTF8Encoding();
                byte[] xmlBytes = converter.GetBytes(xmlText);

                //在 HTTP 头信息中写入报表数据压缩信息
                response.AppendHeader("gr_zip_type", "deflate"); //指定压缩方法
                response.AppendHeader("gr_zip_size", xmlBytes.Length.ToString()); //指定数据的原始长度
                response.AppendHeader("gr_zip_encode", converter.HeaderName); //指定数据的编码方式 utf-8 utf-16 ...

                // 把压缩后的xml数据发送给客户端
                var compressedzipStream = new DeflateStream(response.OutputStream,
                    CompressionMode.Compress, true);
                compressedzipStream.Write(xmlBytes, 0, xmlBytes.Length);
                compressedzipStream.Close();
            }
            else
            {
                // 把xml对象发送给客户端
                //DataPage.Response.ContentType = "text/xml";
                response.Write(xmlText);
            }

            //报表XML数据的前后不能附加任何其它数据，否则XML数据将不能成功解析，所以调用End方法放弃网页中后面不必要的数据
            response.End();
        }

        ////分批读取报表数据实，从IDataReader中产生一个批次的报表XML数据
        //public static int BatchGenXmlDataFromDataReader(System.Web.UI.Page DataPage, IDataReader dr, int WantRows, bool ToCompress)
        //{
        //    string XMLText = "<xml>\n";
        //    int ReadedRows = 0;
        //    while (dr.Read() && (ReadedRows < WantRows))
        //    {
        //        XMLText += "<row>";
        //        for (int i = 0; i < dr.FieldCount; ++i)
        //        {
        //            string FldName = dr.GetName(i);
        //            if (FldName == "")
        //                FldName = "Fld" + i;

        //            if (dr.GetFieldType(i).IsArray)
        //            {
        //                long DataSize = dr.GetBytes(i, 0, null, 0, int.MaxValue);
        //                byte[] buffer = new byte[DataSize];
        //                dr.GetBytes(i, 0, buffer, 0, (int)DataSize);
        //                XMLText += String.Format("<{0}>{1}</{0}>\r\n", FldName, Convert.ToBase64String(buffer));
        //            }
        //            else
        //            {
        //                XMLText += String.Format("<{0}>{1}</{0}>\r\n", FldName, HttpUtility.HtmlEncode(dr.GetValue(i).ToString()));
        //            }
        //        }
        //        XMLText += "</row>\n";
        //        ++ReadedRows;
        //    }
        //    XMLText += "</xml>\n";

        //    ResponseXml(DataPage, ref XMLText, ToCompress);

        //    return ReadedRows;
        //}

        ////分批读取报表数据实，从DataTable中产生一个批次的报表XML数据，如果是第一批，在头部信息中指定记录数据个数
        //public static int BatchGenXmlDataFromDataTable(System.Web.UI.Page DataPage, DataTable dt, int StartNo, int WantRows, bool ToCompress)
        //{
        //    //如果是第一次取数，在Http头中指定记录数，以便客户端在开始时就产生准确的分页信息
        //    if (StartNo == 0)
        //        DataPage.Response.AppendHeader("gr_batch_total", dt.Rows.Count.ToString());

        //    string XMLText = "<xml>\n";
        //    int ReadedRows = 0;
        //    while ((StartNo < dt.Rows.Count) && (ReadedRows < WantRows))
        //    {
        //        DataRow Row = dt.Rows[StartNo];
        //        XMLText += "<row>";
        //        for (int i = 0; i < dt.Columns.Count; ++i)
        //        {
        //            string FldName = dt.Columns[i].ColumnName;
        //            if (FldName == "")
        //                FldName = "Fld" + i;

        //            if (Row[i].GetType().IsArray)
        //            {
        //                XMLText += String.Format("<{0}>{1}</{0}>\r\n", FldName, Convert.ToBase64String((byte[])Row[i]));
        //            }
        //            else
        //            {
        //                XMLText += String.Format("<{0}>{1}</{0}>\r\n", FldName, HttpUtility.HtmlEncode(Row[i].ToString()));
        //            }
        //        }
        //        XMLText += "</row>\n";
        //        ++ReadedRows;
        //        ++StartNo;
        //    }
        //    XMLText += "</xml>\n";

        //    ResponseXml(DataPage, ref XMLText, ToCompress);

        //    return ReadedRows;
        //}



    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    //class JSONReportData 产生报表需要的 JSON 格式数据
    public class JsonReportData
    {

        //根据DataSet, 产生提供给报表需要的XML数据，参数ToCompress指定是否压缩数据
        public static void GenDetailData(System.Web.UI.Page dataPage, DataSet myds, bool toCompress)
        {
            GenDetailData(dataPage, myds.Tables[0], toCompress);
        }

        public static void GenDetailData(HttpResponse response, DataSet myds, bool toCompress)
        {
            GenDetailData(response, myds.Tables[0], toCompress);
        }

        //根据DataTable, 产生提供给报表需要的XML数据，参数ToCompress指定是否压缩数据
        public static void GenDetailData(System.Web.UI.Page dataPage, DataTable dt, bool toCompress)
        {
            GenDetailData(dataPage.Response, dt, toCompress);
        }

        public static void GenDetailData(HttpResponse response, DataTable dt, bool toCompress)
        {
            string Out = GenDetailText(dt);
            XmlReportData.ResponseXml(response, ref Out, toCompress);
        }

        //根据DataSet, 产生提供给报表需要的XML数据，并同时将ParamterPart中的报表参数数据一起打包，参数ToCompress指定是否压缩数据
        public static void GenEntireData(System.Web.UI.Page dataPage, DataSet myds, ref string parameterPart,
            bool toCompress)
        {
            GenEntireData(dataPage.Response, myds, ref parameterPart, toCompress);
        }

        public static void GenEntireData(HttpResponse response, DataSet myds, ref string parameterPart,
            bool toCompress)
        {
            string xmlText = GenDetailText(myds.Tables[0]);

            StringBuilder sb = new StringBuilder(xmlText, 0, xmlText.Length - 1,
                xmlText.Length + parameterPart.Length + 2); //去掉最后一个“}”
            sb.Append(',');
            sb.Append(parameterPart);
            sb.Append('}');
            string Out = sb.ToString();
            XmlReportData.ResponseXml(response, ref Out, toCompress);
        }

        //根据 IDataReader 产生提供给报表需要的XML参数数据包
        public static void GenParameterData(System.Web.UI.Page dataPage, IDataReader drParamer)
        {
            GenParameterData(dataPage.Response, drParamer);
        }

        public static void GenParameterData(HttpResponse response, IDataReader drParamer)
        {
            string sbJsonText = GenParameterText(drParamer);
            sbJsonText = "{" + sbJsonText + "}";
            XmlReportData.ResponseXml(response, ref sbJsonText, false);
        }

        //根据DataTable, 产生提供给报表需要的JSON文本数据
        public static string GenDetailText(DataTable dt)
        {
            var sbJsonText = new StringBuilder("{\"recordset\":[\n");
            foreach (DataRow dr in dt.Rows)
            {
                sbJsonText.Append('{');
                //bool IsFirst = true;
                for (int i = 0; i < dt.Columns.Count; ++i)
                {
                    if (!dr.IsNull(i))
                    {
                        string value;
                        if (dt.Columns[i].DataType.IsArray)
                        {
                            value = Convert.ToBase64String((byte[])dr[i]);
                        }
                        else
                        {
                            value = dr[i].ToString();
                            PrepareValueText(ref value);
                        }
                        sbJsonText.AppendFormat("\"{0}\":\"{1}\",", dt.Columns[i].ColumnName, value);
                    }
                }
                sbJsonText.Remove(sbJsonText.Length - 1, 1); //去掉每笔记录最后一个字段后面的","
                sbJsonText.Append("},\n");
            }
            sbJsonText.Remove(sbJsonText.Length - 2, 1); //去掉最后一条记录后面的","
            sbJsonText.Append("]}");

            return sbJsonText.ToString();
        }

        //将 DataReader 中的数据打包为报表需要的参数数据包形式
        public static string GenParameterText(IDataReader drParamer)
        {
            var sbJsonText = new StringBuilder();
            if (drParamer.Read())
            {
                for (int i = 0; i < drParamer.FieldCount; ++i)
                {
                    if (drParamer.IsDBNull(i))
                        continue;

                    string value;
                    if (drParamer.GetFieldType(i).IsArray)
                    {
                        long dataSize = drParamer.GetBytes(i, 0, null, 0, int.MaxValue);
                        byte[] buffer = new byte[dataSize];
                        drParamer.GetBytes(i, 0, buffer, 0, (int)dataSize);
                        value = Convert.ToBase64String(buffer);
                    }
                    else
                    {
                        value = drParamer.GetValue(i).ToString();
                        PrepareValueText(ref value);
                    }

                    sbJsonText.AppendFormat("\"{0}\":\"{1}\",", drParamer.GetName(i), value);
                }
            }
            sbJsonText.Remove(sbJsonText.Length - 1, 1); //去掉最后一个字段后面的","
            return sbJsonText.ToString();
        }

        //如果数据中包含有JSON规范中的特殊字符(" \ \r \n \t)，多特殊字符加 \ 编码
        public static void PrepareValueText(ref string valueText)
        {
            bool hasSpecialChar = false;
            foreach (char ch in valueText)
            {
                if (ch == '"' || ch == '\\' || ch == '\r' || ch == '\n' || ch == '\t')
                {
                    hasSpecialChar = true;
                    break;
                }
            }
            if (hasSpecialChar)
            {
                var newValueText = new StringBuilder();
                foreach (char ch in valueText)
                {
                    if (ch == '"' || ch == '\\' || ch == '\r' || ch == '\n' || ch == '\t')
                    {
                        newValueText.Append('\\');
                        if (ch == '"' || ch == '\\')
                            newValueText.Append(ch);
                        else if (ch == '\r')
                            newValueText.Append('r');
                        else if (ch == '\n')
                            newValueText.Append('n');
                        else if (ch == '\t')
                            newValueText.Append('t');
                    }
                    else
                    {
                        newValueText.Append(ch);
                    }
                }
                valueText = newValueText.ToString();
            }
        }
    }
}